<template>
  <div class="c_scroll">
    <div class="scroll_head">
      <slot name="head"></slot>
    </div>
    <div class="scroll_wrap"
         id="scroll_wrap"
         ref="wrapper">
      <div class="scroll_list"
           ref="scroll">
        <div class="loading"
             v-show="isUpdate">
          <spinner type="bubbles"
                   :size="6" />
          <!-- <spinner class="spinner"
                   type="bubbles"></spinner> -->
        </div>
        <div class="scroll_content"
             ref="scrollContent">
          <slot></slot>
          <!-- 显示没有数据 -->
          <!-- <p class="no-data"
             v-show="noData && !list.length && !isLoading">{{noData}}</p> -->
          <!-- <p class="no-data"
             v-show=" !list.length && !isLoading"></p> -->
          <!-- v-show="isLoading && !isUpdate" -->
          <div class="loading"
               v-show="!(isEnd || !pullup)"
               :style="{opacity:isLoading && !isUpdate ? 1 : 0}"
               ref="loading">
            <spinner type="bubbles"
                     :size="6" />
            <!-- <spinner class="spinner"
                     type="bubbles"></spinner> -->
            <span class="loading-txt">正在加载</span>
          </div>
          <slot name="foot"></slot>
        </div>
        <!-- 显示加载更多提示 -->
        <!-- <div class="no-more add-more"
             v-show="!isLoad && !isEnd && pullup">
          <span class="line"></span>
          <span class="content">松开加载更多</span>
          <span class="line"></span>
        </div> -->
        <div class="no-more"
             v-show="(isEnd || !pullup) && showNoMore">
          <span class="line"></span>
          <span class="content">我是有底线的</span>
          <span class="line"></span>
        </div>
      </div>
    </div>
  </div>
</template>

<script type="text/ecmascript-6">
import BScroll from 'better-scroll'
// import { Spinner } from 'vux'
import Spinner from './spinner'

export default {
  name: 'CScroll',
  props: {
    /**
     * 1 滚动的时候会派发scroll事件，会截流。
     * 2 滚动的时候实时派发scroll事件，不会截流。
     * 3 除了实时派发scroll事件，在swipe的情况下仍然能实时派发scroll事件
     */
    probeType: {
      type: Number,
      default: 1
    },
    /**
     * 点击列表是否派发click事件
     */
    click: {
      type: Boolean,
      default: true
    },
    /**
     * 是否开启横向滚动
     */
    scrollX: {
      type: Boolean,
      default: false
    },
    /**
     * 是否派发滚动事件
     */
    listenScroll: {
      type: Boolean,
      default: false
    },
    /**
     * 列表的数据
     */
    list: {
      type: Array,
      default: () => { return [] }
    },
    /**
     * 是否派发滚动到底部的事件，用于上拉加载
     */
    pullup: {
      type: Boolean,
      default: true
    },
    /**
     * 是否派发顶部下拉的事件，用于下拉刷新
     */
    pulldown: {
      type: Boolean,
      default: false
    },
    /**
     * 是否派发列表滚动开始的事件
     */
    beforeScroll: {
      type: Boolean,
      default: false
    },
    /**
     * 当数据更新后，刷新scroll的延时。
     */
    refreshDelay: {
      type: Number,
      default: 20
    },
    /**
     *  正在获取数据
     */
    isLoading: {
      type: Boolean,
      default: false
    },
    /**
     *  数据加载完毕
     */
    isEnd: {
      type: Boolean,
      default: false
    },
    // 是否使用css3 transition 动画
    useTransition: {
      type: Boolean,
      default: false
    },
    noData: {
      type: String,
      default: '没有相关数据~'
    },
    preventDefaultException: {
      type: Object,
      default () {
        return {}
      }
    },
    tagException: {
      type: Object,
      default () {
        return {}
      }
    },
    preventDefault: {
      type: Boolean,
      default: true
    },
    // 加载完毕后，是否显示‘我是有底线的’
    showNoMore: {
      type: Boolean,
      default: true
    }
  },
  data () {
    return {
      isUpdate: false,
      isLoad: false,
      timer: null,
      wrapperHeight: 0,
      curPosY: 0,
      scroll: {}
    }
  },
  mounted () {
    // 保证在DOM渲染完毕后初始化better-scroll
    setTimeout(() => {
      this._initScroll()
    }, 20)
  },
  methods: {
    _initScroll () {
      if (!this.$refs.wrapper) {
        return
      }
      if (this.$refs.scroll) {
        this.wrapperHeight = this.$refs.wrapper.offsetHeight

        this.$refs.scroll.style.minHeight = this.wrapperHeight + 'px'
        // this.$refs.scroll.style.minHeight = (this.$refs.wrapper.offsetHeight + this.$refs.loading.offsetHeight) + 'px'
        this.$refs.scrollContent.style.minHeight = (this.wrapperHeight + 1) + 'px'
      }

      // better-scroll的初始化
      this.scroll = new BScroll(this.$refs.wrapper, {
        probeType: this.probeType,
        click: this.click,
        scrollX: this.scrollX,
        useTransition: this.useTransition,
        preventDefaultException: this.preventDefaultException,
        tagException: this.tagException,
        preventDefault: this.preventDefault
      })

      // 是否派发滚动事件
      if (this.listenScroll) {
        this.scroll.on('scroll', (pos) => {
          this.$emit('scroll', pos)
        })
      }

      // 是否派发滚动到底部事件，用于上拉加载
      if (this.pullup) {
        let isScrollLoad = false
        this.scroll.on('touchEnd', (pos) => {
          // 下拉动作
          if (pos.y <= -50) {
            // if (pos.y <= this.scroll.maxScrollY - 25) {
            isScrollLoad = true
          } else {
            isScrollLoad = false
          }
        })
        this.scroll.on('scrollEnd', (pos) => {
          // 滚动到底部
          if (this.scroll.y <= (this.scroll.maxScrollY) && isScrollLoad) {
            if (!this.isEnd && this.pullup) {
              this.isLoad = true
              this.disable()
              this.$emit('pullup')
            }
          }
        })
      }

      // 是否派发顶部下拉事件，用于下拉刷新
      if (this.pulldown) {
        this.scroll.on('touchEnd', (pos) => {
          // 下拉动作
          if (pos.y > 50 && this.pulldown) {
            this.isUpdate = true
            this.$emit('pulldown')
          }
        })
      }

      // 是否派发列表滚动开始的事件
      if (this.beforeScroll) {
        this.scroll.on('beforeScrollStart', () => {
          this.$emit('beforeScroll')
        })
      }
    },
    disable () {
      // 代理better-scroll的disable方法
      this.scroll && this.scroll.disable && this.scroll.disable()
    },
    enable () {
      // 代理better-scroll的enable方法
      this.scroll && this.scroll.enable && this.scroll.enable()
    },
    refresh () {
      this.enable()
      // 代理better-scroll的refresh方法
      this.scroll && this.scroll.refresh && this.scroll.refresh()
    },
    stop () {
      this.scroll && this.scroll.stop()
    },
    scrollTo () {
      // 代理better-scroll的scrollTo方法
      this.scroll && this.scroll.scrollTo.apply(this.scroll, arguments)
    },
    scrollToElement () {
      // 代理better-scroll的scrollToElement方法
      this.scroll && this.scroll.scrollToElement.apply(this.scroll, arguments)
    },
    // 滚动到顶部
    scrollToTop (time) {
      let duration = time || 500
      this.scroll.bounce = false
      this.scroll && this.scrollTo.call(this.scroll, 0, 0, duration)
    },
    // 滚动到底部
    scrollToBottom (data, time) {
      // var scroll = new BScroll(this.$refs.scrollContent)
      // this.$nextTick(() => {
      //   console.log('scrollContent', scroll, scroll.maxScrollY)
      //   let children = this.$refs.scrollContent.children
      //   console.log('child', children[0])
      //   let newChildHeight = children[0].clientHeight
      //   console.log('maxScrollY', this.scroll.maxScrollY, -newChildHeight)
      // })
      this.scroll.bounce = false
      this.scroll && this.scrollTo.call(this.scroll, 0, data, time)
      // this.scroll && this.
    },
    changeMinHeight () {
      this.$nextTick(() => {
        if (this.$refs.scroll) {
          let height = this.$refs.wrapper.offsetHeight - this.wrapperHeight
          if (!height) return
          this.wrapperHeight = this.$refs.wrapper.offsetHeight

          this.$refs.scroll.style.minHeight = (this.wrapperHeight) + 'px'
          this.$refs.scrollContent.style.minHeight = (this.wrapperHeight + 1) + 'px'
        }
      })
    }
  },
  watch: {
    // 监听数据的变化，延时refreshDelay时间后调用refresh方法重新计算，保证滚动效果正常
    list () {
      setTimeout(() => {
        this.refresh()
      }, this.refreshDelay)
    },
    isLoading (nVal) {
      if (nVal) {
        return
      }
      if (this.isUpdate) {
        this.isUpdate = false
      }
      if (this.isLoad) {
        this.isLoad = false
      }
    }
  },
  components: {
    Spinner
  },
  activated () {
    this.changeMinHeight()
  }
}
</script>

<style lang="stylus" rel="stylesheet/stylus" scoped>
.c_scroll >>> .vux-spinner
  stroke $color-font-l
  fill $color-font-l
.c_scroll
  positionFull()
  display flex
  flex-direction column
  overflow hidden
  transform translateZ(0)
  .scroll_head
    position relative
    z-index 1
  .scroll_wrap
    flex 1
    height 0
  .load_icon
    width 20px
  .scroll_list
    position relative
    min-height 100vh
  .loading
    display flex
    justify-content center
    align-items center
    padding 7px 0
    transition all 0.3s
    .loading-txt
      margin-left 15px
      color $color-font-l
      font-size 12px
  .no-more
    position absolute
    right 0
    bottom 0
    left 0
    display flex
    justify-content center
    align-items center
    padding-top 30px
    transform translate(0, 100%)
    span
      display block
    .content
      margin 0 5px
      color $color-font-l
      font-size 12px
    .line
      width 70px
      height 1px
      background-color $color-font-l
      transform scale(1, 0.5)
  .add-more
    padding-top 15px
  .no-data
    padding 50px 0
    color $color-font-l
    text-align center
    font-size 12px
</style>
